package com.pajk.user.api;

import com.pajk.commons.types.VersionedValue;
import com.pajk.user.exception.UserServiceHttpCode;
import com.pajk.user.model.InviteeFolloweeInfo;
import com.pajk.user.model.UserRelation;
import com.pajk.user.model.enums.ChannelType;
import com.pajk.user.model.enums.Gender;
import com.pajk.user.model.enums.RelationType;
import com.pajk.user.model.User;

import net.pocrd.annotation.*;
import net.pocrd.define.ApiOpenState;
import net.pocrd.define.CommonParameter;
import net.pocrd.define.SecurityType;
import net.pocrd.entity.CallerInfo;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 用户服务接口
 *
 * @author Haomin Liu, Sean Gao
 */
public interface UserService {

    /**
     * 通过查询（OpenID ＋ ChannelID）获取User对象
     * 通常可以用在渠道应用登录的场景
     *
     * @param openId 某个渠道中的用户唯一识别ID
     * @param from 渠道号
     * @return 查询则直接范围用户实体，否则看Result中会有错误嘛
     */
    public User getUserByOpenId(String openId, ChannelType from);

    /**
     * 根据userId获取用户信息
     *
     * @param userId 人员ID
     * @return 查询成功则直接范围用户实体，否则看Result中会有错误嘛
     */
    public User getUserById(Long userId);

    /**
     * 根据手机号获取用户信息
     *
     * @param mobile 用户手机号
     * @return 查询成功则直接范围用户实体，否则看Result中会有错误嘛
     */
    public User getUserByMobile(Long mobile);

    /**
     * 用渠道的OpenId获取或创建用户
     * 当通过公众帐号登录时,发现没有关系的人员信息,可以发起快速人员的请求
     *
     * @param openId 用户在渠道中的唯一标示号
     * @param from 渠道号
     * @return 创建成功则直接范围用户实体，否则看Result中会有错误嘛
     */
    public User getOrCreateUserByOpenId(String openId, ChannelType from);

    /**
     * 创建新用户
     *
     * @param user 初始值
     * @return 创建成功则直接返回用户实体，否则返回空
     */
    public User createUser(User user);

    /**
     * 修改用户信息
     *
     * 约定：
     * 1. 只能修改简单属性类型的域（User对象中拥有public set函数的域）；
     * 2. 那些有唯一性约束（例如手机号），复杂业务逻辑的域（例如积分），只能通过本接口其他方法显示修改；
     *
     * 举例：
     *
     * <code>
     *     User changes = new User();
     *     changes.setCertType(CertificationType.ID);
     *     changes.setCertId(510104198009144115L);
     *
     *     // 假设在之前的代码中已经拿到要修改的user对象
     *     // 这句话将更新此用户的身份证类型和身份证号
     *     userService(user.getId(), changes);
     * </code>
     *
     * @param changes
     * @return
     */
    
    public void updateUserInfo(Long userId, User changes);
    
    

    
    
    /**
     * 更新用户的健康积分
     * @param userId 用户ID
     * @param credit 新加的积分
     */
    public void updateUserCredits(Long userId, int credit);
    
    /**
     * 更改用户手机号
     *
     * 约定：手机号一旦设定，必须符合唯一性约束
     *
     * @param userId 更改手机号用户ID
     *
     */
    public Boolean updateMobile(Long userId, Long mobile);


    /**
     * 切换User档案
     * 将指向oldUser的所有渠道账号全部指向newUser
     *
     * 逻辑约定：如果两个UserID有相同渠道的两个OpenId冲突，则不能操作
     *
     * @param oldUserId 需要转出的userId
     * @param newUserId 需要转入的userId
     *
     */
    public void mergeAccountChannel(Long oldUserId, Long newUserId);

    /**
     * 绑定万里通帐号
     *
     * @param userId 用户Id
     * @param wltAccountId 万里通帐号Id
     *
     */
    public Boolean bindWltAccount(Long userId, String wltAccountId);

    /**
     * 快速创建关注用户
     * 为某用户创建人员并增加关注关系
     *
     * @param followerId 为此用户创建创建关注用户
     * @param followee 需要快速创建的被关注用户实体
     * @param followReason 关注类型，比如配偶、孩子等
     * @param floweeNick 被关注者昵称
     * @return 被关注用户id
     */
    @Deprecated
    public long createFollowee(Long followerId, User followee, RelationType followReason, String floweeNick);

    /**
     * 快速创建关注用户
     * 为某用户创建人员并增加关注关系
     *
     * @param followerId 为此用户创建创建关注用户
     * @param followee 需要快速创建的被关注用户实体
     * @param followReason 关注类型，比如配偶、孩子等
     * @param floweeNick 被关注者昵称
     * @return 被关注用户id
     */
    public long createFollowee(Long followerId, User followee, RelationType followReason, String floweeNick,String appFrom);

    /**
     * 添加关注
     * 为followerId用户增加关注关系
     *
     * @param followerId 为此用户创建创建关注用户
     * @param followee 被关注用户
     * @param followReason 关注类型，比如配偶、孩子等
     *
     */
    @Deprecated
    public boolean addFollowee(Long followerId, User followee, RelationType followReason, String floweeNick);

    /**
     * 添加关注
     * 为followerId用户增加关注关系
     *
     * @param followerId 为此用户创建创建关注用户
     * @param followee 被关注用户
     * @param followReason 关注类型，比如配偶、孩子等
     *
     */
    public boolean addFollowee(Long followerId, User followee, RelationType followReason, String floweeNick,String appFrom);

    /**
     * 解除follower对followee的关注
     *
     * @param followerId 解除follower对followee的关注
     * @param followeeId 解除follower对followee的关注
     *
     */
    public boolean cancelFollow(Long followerId, Long followeeId);

    /**
     * 修改关注信息
     *
     * @param followerId 当前用户
     * @param followee 关注用户
     * @param followReason 关注类型，比如配偶、孩子等
     * @return 修改结果
     */
    public boolean updateUserRelation(Long followerId, User followee, RelationType followReason, String floweeNick);

    /**
     * 修改关注信息
     *
     * @param followerId 当前用户
     * @param followeeId 关注用户Id
     * @param followReason 关注类型，比如配偶、孩子等
     * @return 修改结果
     */
    public boolean updateUserRelation(Long followerId, Long followeeId, RelationType followReason, String floweeNick);

    /**
     * 查询userId用户所关注的用户列表
     *
     *
     * @param userId 要查询的用户ID
     * @return 用户关系实体列表
     */
    public List<UserRelation> getFollowees(Long userId);

    /**
     * 检查两个user之间是否存在从from指向to的关系
     *
     * @param from 关系起始用户
     * @param to 关系结束用户
     * @return 用户关系实体
     */
    public UserRelation checkRelation(Long from, Long to);


    /**
     * 查询所有关注了userId的用户列表
     *
     *
     * @param userId 要查询的用户ID
     * @return 用户ID列表
     */
    //public List<Long> getFollowers(Long userId);

    /**
     * 获取指定userId指定domain下的完整扩展属性
     *
     * @param userId 用户ID
     * @param domain domain
     * @return Map格式的属性数据：键->带版本的值，无查询结果返回null
     */
    public Map<String, VersionedValue<String>> getUserExtAll(Long userId, String domain);

    /**
     * 获取指定userId指定domain下指定键的值
     *
     * @param userId 用户ID
     * @param domain domain
     * @param extKey 属性键
     * @return 带版本的值，无查询结果返回null
     */
    public VersionedValue<String> getUserExtData(Long userId, String domain, String extKey);

    /**
     * 设置指定userId指定domain下指定键的扩展属性值，如无原值则新建
     *
     * @param userId 用户ID
     * @param domain domain
     * @param extKey 属性键
     * @param extData 属性值，最大长度4000个字符
     * @param lastSeenVersion 当前属性值的版本号，若为新建则传null，用作乐观锁
     */
    public void setUserExtData(Long userId, String domain, String extKey, String extData, Long lastSeenVersion);

    /**
     * 取消/删除指定userId指定domain下指定键值对
     *
     * @param userId 用户ID
     * @param domain domain
     * @param extKey 属性键
     * @param lastSeenVersion 当前已知属性值的版本号，用作乐观锁
     */
    public void removeUserExtData(Long userId, String domain, String extKey, Long lastSeenVersion);
    
    /**
     * @param deviceId
     * @param userId
     * @return 1:是用户的受信设备 2:处于激活状态  -1:不是用户的受信设备
     */
    int getUserDeviceBindingState(Long deviceId, Long userId);
    
    /**
     * @param deviceId 设备id
     * @param mobile 手机号
     * @param smsPass 短信动态码
     * @return
     */
    CallerInfo getUserInfoBySmsPass(Long deviceId, Long mobile, String smsPass);
    
    /**
     * User合并
     * 将指向oldUser的账号指向newUser
     *
     *
     * @param oldUserId 需要转出的userId
     * @param newUserId 需要转入的userId
     *
     */
    void mergeUser(Long oldUserId, Long newUserId);

    /**
     * 邀请用户注册关添加关注
     *
     * @param inviterUserId 邀请者userId
     * @param inviteeMobile 被邀请人手机号
     * @param inviteeFolloweeInfoList 被邀请人所需要关注者列表
     * @param appFrom 发起邀请的系统
     * @param businessBody 业务消息体
     */
    void inviteUser(Long inviterUserId, String inviteeMobile, List<InviteeFolloweeInfo> inviteeFolloweeInfoList,String appFrom,String messageCode,String businessBody);

}

